package Busquedas;

import Problemas.Problema;
import java.util.ArrayList;


/**
 * Clase para implementar la b�squeda de profundidad iterativa.
 * Extiende de la clase B�squeda.
 
 */
public class ProfundizacionIterativa extends Busqueda {

	protected boolean solucionado;
	protected Nodo ini;
	
	
	/**
	 * Constructor de la b�squeda. Llama a la constructora de B�squeda, su clase padre.
	 * @param p Problema que queremos resolver con la b�squeda A*.
	 */
	public ProfundizacionIterativa(Problema p) {
		super(p);
	}

	/* (non-Javadoc)
	 * @see Busqueda#buscar(boolean)
	 */
	@Override
	public ArrayList<Estado> buscar(boolean controlCiclos){
		int limite=1;
		solucionado=false;
		int nivelActual=0;
		abiertos.add(this.getNodo()); //se a�ade la ra�z
		ini=this.getNodo();
		Nodo n;
		expandidos.add(this.getNodo().getEstado());
		int op=0;
		long tiempo1=System.currentTimeMillis();
		try{	
			while ((!solucionado)){
				contadorNodos=0;
				while((!abiertos.isEmpty())&& (nivelActual<=limite)){
					contadorNodos++;
					if (contadorNodos>maxContadorNodos) return null;
					//System.out.println("-> limite : "+limite+" nivel : "+nivelActual+" "+abiertos);
					n = abiertos.get(abiertos.size()-1);
					//if (op<this.getProblema().getnumOper())this.dibujaNodos(op,n,n.getEstado());
					if (!this.getProblema().estadoFinal(n.getEstado())){
						solucionado=false;
						if ((op==this.getProblema().getnumOper())|| (nivelActual==limite)){					
							abiertos.remove(abiertos.size()-1);
							n=n.getPadre();
							nivelActual--;
							op=0;
							
						}else if (n.getOperadoresAplicados()[op]==1){
							op++;
						}else {
							Estado e=this.getProblema().aplicaOperador(n.getEstado(), op);
							//this.dibujaNodos(op,n,e);
							n.setOperadoresAplicados(op);
							if (e!=null){
								if ((!(controlCiclos && estaEnExpandidos(e)))&& (nivelActual<limite)){
									Nodo n2=n.anadeHijo(op,e,this.getProblema().getCosteOperador(op)/*,this.dibuja*/);
									//if (n2.getPadre()!=abiertos.get(abiertos.size()-1)){nivelActual++;}
									abiertos.add(n2);
									nivelActual++;
									expandidos.add(n.getEstado());
									int inverso = this.getProblema().getOperadorInverso(op);
									if (inverso != -1) 
										n2.setOperadoresAplicados(inverso);
									op=0;
								}
							}else {
								op++;
							}
						}
					}else{
						solucionado=true;
						long tiempo2=System.currentTimeMillis();
						this.setTiempoTotal((tiempo2-tiempo1));
						generaCamino(n);
						return camino;
					}		
				}
				limite++;
				nivelActual=0;
				n=new Nodo(ini.getEstado(),ini.getNumMaxHijos(),op);
				abiertos.clear();
				abiertos.add(n);
				expandidos.clear();
				if (controlCiclos) expandidos.add(n.getEstado());
				op=0;
				//System.out.println("limite : "+limite+" nivel : "+nivelActual);
				
			}
		}catch(OutOfMemoryError e){
			abiertos = null;
			return null;
		}
		return null;
	}
	

}
